/**
 **************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************
 * @file RBRenderer.h
 **************************************************************************************************************************************************************/

#ifndef __RBRENDERER_H__
#define __RBRENDERER_H__

#ifdef  HEADER_ONCE
#pragma HEADER_ONCE
#endif

#ifdef  HEADER_MSG
#pragma HEADER_MSG(RBRenderer.h)
#endif

/**************************************************************************************************************************************************************
 * Includes
 **************************************************************************************************************************************************************/
#include "RBRefObject.h"
#include "RBSingleton.h"

#include "RBHandle.h"
#include "RBGeometryPrimitiveType.h"
#include "RBRenderState.h"
#include "RBSamplerState.h"


/**************************************************************************************************************************************************************
 * Forward declarations
 **************************************************************************************************************************************************************/
class RBCamera;
class RBGeometry;
class RBHardwareBufferManager;
class RBIndexBuffer;
class RBLight;
class RBMaterial;
class RBRenderTargetGroup;
class RBTexture;
class RBTextureSampler;
class RBPixelBuffer;
class RBVertexBuffer;
class RBVertexDeclaration;
class RBEffectTechnique;
struct RBShader;
class RBShaderResourceView;
class RBShaderSamplerState;
class RBHardwareBuffer;
class RBRasterizerState;
class RBDepthStencilState;
class RBBlendState;
class RBViewPort;
struct RBRenderTargetView;
struct RBDepthStencilView;

RBDeclareHandle(RBGeometry);
RBDeclareHandle(RBCamera);

/**************************************************************************************************************************************************************
 * Classes
 **************************************************************************************************************************************************************/

struct rb_locked_data
{
    void* Data;
    uint32 Pitch;
};

class RBRenderer : public RBRefObject, public RBSingleton<RBRenderer>
{
    RBDeclareRTTI(RBRenderer, RBRefObject);
public:
    static const uint32 ms_uiRenderTargetCount = 4;
    static const uint32 ms_uiMaxConstantBuffers = 16;
    static const uint32 ms_uiMaxShaderResources = 16;
    static const uint32 ms_uiMaxSamplers = 16;
    static       float  ms_near;

    enum                        ClearFlags          { CF_COLOR    = 1 << 0, 
                                                      CF_ZBUFFER  = 1 << 1, 
                                                      CF_STENCIL  = 1 << 2,
                                                      CF_ALL = CF_COLOR | CF_ZBUFFER | CF_STENCIL};

    enum                        ColorWrite          {
                                                      COLOR_WRITE_RED    = 1 << 0,
                                                      COLOR_WRITE_GREEN  = 1 << 1,
                                                      COLOR_WRITE_BLUE   = 1 << 2,
                                                      COLOR_WRITE_ALPHA  = 1 << 3,
                                                      COLOR_WRITE_ALL    = (COLOR_WRITE_RED | COLOR_WRITE_GREEN | COLOR_WRITE_BLUE | COLOR_WRITE_ALPHA)
                                                    };

    template<class Renderer, class RendererInit>
    static Renderer*            Create              (const RendererInit& init);

    virtual bool                Init                ();
    virtual void                Release             ();

    virtual void                UpdateCamera        (RBCamera* camera);

    virtual void                Render              (RBHandle<RBGeometry> pGeometry);

    RBRenderTargetView*         GetBackBuffer       ();
    RBDepthStencilView*         GetDepthStencil     ();
    RBRenderTargetGroup*        GetDefaultGroup     ();

    RBHardwareBufferManager*    GetHBMgr            ();
    const RBCamera*             GetViewProj         () const;

    const float4x4&             GetView             () const { return m_View; }
    const float4x4&             GetProj             () const { return m_Proj; }

    float4x4                    BuildProjMatrix     (RBCamera* camera);

    virtual void                ChangeResolution    (uint32 /*uiWidth*/, uint32 /*uiHeight*/) {}

    virtual bool                RestoreLostDevice   (bool bForceReset = false);

    typedef fastdelegate::FastDelegate<void(bool)> ResetFunction;

    uint32                      AddResetFunction    (ResetFunction func);
    void                        RemoveResetFunction (uint32 ui);

    virtual void                Swap                () = 0;
	virtual void                Flush               () = 0;
    void                        clear_state         ();

    void                        Lock                (RBTexture* texture, uint32 mapType, rb_locked_data* pMapped, uint32 sub_resource=0);
    void                        Unlock              (RBTexture* texture, uint32 sub_resource=0);

    virtual void                Map                 (void* pResource, uint32 mapType, rb_locked_data* pMapped, uint32 sub_resource=0) = 0;
    virtual void                Unmap               (void* pResource, uint32 sub_resource=0) = 0;

    virtual void                IASetVertexBuffer   (uint32 uiStream, const RBVertexBuffer* pVertexBuffer, bool bUseInstancing = false) = 0;
    virtual void                IASetVertexDecl     (const RBVertexDeclaration* pVertexDecl) = 0;
    virtual void                IASetIndexBuffer    (const RBIndexBuffer* pIndexBuffer) = 0;
    virtual void                IASetTopology       (RBGeometryPrimitiveType::EType ePT) = 0;

    virtual void                OMSetRenderTargets  (uint32 view_count, const RBRenderTargetView* const* colors, RBDepthStencilView* depth) = 0;

    virtual void                ClearRenderTargets  (RBRenderTargetGroup* pRenderTargetGroup, const RBColorA& color, float32 clearZ, uint32 clearFlags) = 0;

    virtual void                VSSetShader         (const RBShader* pShader) = 0;
    virtual void                PSSetShader         (const RBShader* pShader) = 0;
    
    virtual void                VSSetConstantBuffers(uint32 uiStart, uint32 uiCount, void** vNativeBuffers) = 0;
    virtual void                PSSetConstantBuffers(uint32 uiStart, uint32 uiCount, void** vNativeBuffers) = 0;
    
    virtual void                VSSetShaderResources(uint32 uiStart, uint32 uiCount, void** vNativeViews) = 0;
    virtual void                PSSetShaderResources(uint32 uiStart, uint32 uiCount, void** vNativeViews) = 0;

    virtual void                VSSetSamplers       (uint32 uiStart, uint32 uiCount, void** vNativeSamplers) = 0;
    virtual void                PSSetSamplers       (uint32 uiStart, uint32 uiCount, void** vNativeSamplers) = 0;

    virtual void                OMSetBlendState     (const RBBlendState* pState) = 0;
    virtual void                RSSetState          (const RBRasterizerState* pState) = 0;
    virtual void                OMSetDepthStencilState (const RBDepthStencilState* pState) = 0;

    virtual void                CopyResource        (RBHardwareBuffer* dst, RBHardwareBuffer* src) = 0;
    virtual void                RSSetViewport       (const RBViewPort& viewport)= 0;

    virtual void                DrawIndexedPrimitive(uint32 uiVertexCount, uint32 uiPrimitiveCount, int32 iBaseVertexIndex, uint32 uiStartIndex) = 0;
    virtual void                DrawPrimitive       (uint32 uiPrimitiveCount, uint32 uiStartVertex) = 0;

    void                        SetColorWrite       (uint32 i, uint8 mask);

                                RBRenderer          ();
    virtual                    ~RBRenderer          ();

protected:

    virtual void                ClearState          () = 0;

    virtual RBHardwareBufferManager* CreateHBMgr    () { return NULL; }

    virtual void                Draw                (const RBGeometry* pGeometry);

protected:
    RBHardwareBufferManager*    m_pHBMgr;
    const RBCamera*             m_pViewCamera;
    float4x4                    m_View;
    float4x4                    m_Proj;
    float4x4                    m_ProjOffsetScale;
    std::vector<ResetFunction>  m_vResetFunctions;
    void*                       m_pShaderConstantData;
    const RBShaderResourceView**m_ppViews;
    const RBShaderSamplerState** m_ppSamplerStates;

    RBRenderTargetView*         m_pBackBuffer;
    RBDepthStencilView*         m_pDepthStencil;
    RBRenderTargetGroup*        m_default_target_group;
    uint32                      m_colorWriteEnable;

    // State caching
    RBRasterizerState*          m_prev_raster;
    RBDepthStencilState*        m_prev_stencil_state;
    RBBlendState*               m_prev_blend_state;
    RBIndexBuffer*              m_prev_idx_buffer;
    RBVertexBuffer*             m_prev_vtx_buffer;
    RBVertexDeclaration*        m_prev_vtx_decl;
    uint32                      m_prev_pt;

};

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
template<class Renderer, class RendererInit>
Renderer* RBRenderer::Create(const RendererInit& init)
{
    // We managed to create a D3D Object: Store all parameters
    Renderer* pThis = new Renderer;
    if (!pThis->Init(init))
    {
        delete pThis;
        pThis = NULL;
    }
    return pThis;

}

#include "RBRenderer.inl"

RBDeclareSmartPointer(RBRenderer);

/**************************************************************************************************************************************************************/

#endif // __RBRENDERER_H__
